import datetime
import os
import matplotlib.pyplot as plot
import matplotlib.ticker as ticker
import numpy as np
'''抽取新版本发布前后各3个月的数据, 做数据集约减;
'''
# Eclipse   product: 74   component: 468
# Mozilla   product: 31   component: 415

def get_msgs_by_reading_file(file):
	'''
	file中文件的格式为 "bug_id", "assigned_to", "creation_ts", "delta_ts", "product", "component"
	:param file: 
	:return: 
	'''
	msgs = []
	with open(file, 'r') as reader:
		for line in reader.readlines():
			temp = line.strip().split('\t')
			# 切割str, 保存成可转换datetime的格式
			temp[2] = temp[2].split(' ')[:-1] # -1位不取, 这是为了删掉后面的时区字符
			temp[2] = transform_str_to_time(' '.join(temp[2]), 0)
			temp[3] = temp[3].split(' ')[:-1]
			temp[3] = transform_str_to_time(' '.join(temp[3]), 1)
			# print(type(temp[2]))
			msgs.append(temp)
	return msgs

def transform_str_to_time(t_str, index):
	'''
	将输入的字符串格式的时间转换成datetime格式用于计算
	:param t_str: 
	:param index: 
	:return: 
	'''
	time_format = ['%Y-%m-%d %H:%M', '%Y-%m-%d %H:%M:%S']   # 很奇怪, creation_ts都是精确到分, 而delta_ts则是精确到秒, 所以二者需要不同的时间解析格式
	return datetime.datetime.strptime(t_str, time_format[index])

def _calculate_daily_bug_nums(msgs, index=2):
	'''
	计算每日的bug数量
	:param msgs: 
	:return: 
	'''
	ts = list(zip(*msgs))[index]  # 提出creation_ts这一列
	cts = list(map(lambda x: str(x).split(' ')[0], ts))     # 删掉时分秒, 只保留年月日
	set_cts = set(cts)      # 这个需要排序, 由小到大
	set_cts = sorted(set_cts, key=lambda x: datetime.datetime.strptime(x, '%Y-%m-%d'))
	# print(set_cts)
	daily_bugs = []

	for day in set_cts:
		daily_bugs.append(cts.count(day))

	# 删掉最大值, 单值过高容易影响图片可视化, 适用于最大值极大的情况
	# max_num = max(daily_bugs)
	# mindex = daily_bugs.index(max_num)
	# set_cts.pop(mindex)
	# daily_bugs.pop(mindex)

	return set_cts, daily_bugs

def extract_bugs_within_the_time_period(msgs, start_time, end_time, index=2):
	'''
	Eclipse V3.0发布时间为2004.6.25, 前后各扩展3个月
	:param msgs: 
	:param elements: 
	:return: 
	'''
	remove_indexs = []     # 需要移除的bug的索引

	for i in range(len(msgs)):
		if msgs[i][index] < start_time or msgs[i][index] > end_time:   # 用creation_ts做比较
			remove_indexs.append(i)
	# 从msgs中删掉remove_ids
	print(len(msgs))
	for index in sorted(remove_indexs, reverse=True):       # 由大到小排列, 以相反的顺序删除, 这样才不会保证丢弃后续索引
		try:
			msgs.pop(index)
		except IndexError as e:
			print(e)
			# pass
			# print(index)
	return msgs     # 返回被过滤之后的msgs

def sorting_bugs_and_write_file(msgs, file):
	'''
	将msgs按照bug_id排序然后写入文件输出
	:param msgs: 
	:param file: 
	:return: 
	'''
	msgs = sorted(msgs, key=lambda bug: bug[0])     # 将bug按照bug_id由小到大排序

	with open(file, 'w') as writer:
		for i in range(len(msgs)):
			writer.write('\t'.join(list(map(str, msgs[i]))))        # 将列表内元素全部转换成str
			writer.write('\n')

def main(root, index, save_file, create=True):
	'''
	程序主入口
	:param root: 
	:param index: 
	:param save_file: 
	:param create: if True, 根据原始文件新建过滤文件, False: 读取之前建立的过滤文件
	:return: 
	'''
	if create:
		msgs = get_msgs_by_reading_file(os.path.join(root, 'bug_msg_all'))
		filtered_msg = extract_bugs_within_the_time_period(msgs, start_time, end_time, index=index)
		sorting_bugs_and_write_file(filtered_msg, os.path.join(root, save_file))
	else:
		filtered_msg = get_msgs_by_reading_file(os.path.join(root, save_file))
	return filtered_msg


def draw_pic(y, x_labels, start_time, end_time, sign):
	x = np.arange(0, len(y), 1)
	# 处理下x轴的刻度, 将年-月-日格式, 转换成月-日格式
	x_labels = ['-'.join(s.split('-')[1:]) for s in x_labels]
	def format_fn(tick_val, tick_pos):
		if int(tick_val) in x:
			return x_labels[int(tick_val)]
		else:
			return ''

	start_time = str(start_time).split(' ')[0]
	end_time = str(end_time).split(' ')[0]

	fig = plot.figure(1)
	axes = fig.add_subplot(111)


	plot.scatter(x, y, alpha=0.6)
	# plot.plot(x, y, 'r-')
	# plot.title("每日fixed的bug数量")
	plot.title(sign)
	plot.xlabel("天数({}~{})".format(start_time, end_time))
	plot.ylabel("bug个数")
	# plot.xticks(x, x_labels)

	axes.xaxis.set_major_formatter(ticker.FuncFormatter(format_fn))     # 实现刻度文本的自定义
	axes.xaxis.set_major_locator(ticker.MultipleLocator(30))        # 每隔30显示一个刻度, 刻度密度
	# axes.xaxis.set_major_locator(ticker.LinearLocator(numticks=None, presets=None))
	# plot.savefig("../data/{}.png".format(sign), bbox_inches='tight', transparent=True, dpi=100)
	plot.show()

if __name__ == '__main__':
	root = "../data/Eclipse"
	# sign = "around6m_submissions"  # 意味着周围6个月的提交记录
	sign = "around12m_fixed"  # 意味着周围6个月的修复记录
	release_time = datetime.datetime.strptime('2004-6-25', '%Y-%m-%d')  # 其实是2004-6-25 0:0
	start_time = datetime.datetime.strptime('2003-12-25', '%Y-%m-%d')
	end_time = datetime.datetime.strptime('2004-12-25', '%Y-%m-%d')
	# start_time = datetime.datetime.strptime('2004-3-25', '%Y-%m-%d')
	# end_time = datetime.datetime.strptime('2004-9-25', '%Y-%m-%d')
	index = 3       # 2指的是提取creation_ts, 3指的是提取delta_ts
	save_file = '{}_{}_bug_msgs'.format(str(release_time).split(' ')[0], sign)

	filtered_msg = main(root, index, save_file, create=True)

	set_ts, daily_bugs = _calculate_daily_bug_nums(filtered_msg, index)

	# 计算评价
	max_num = max(daily_bugs)
	min_num = min(daily_bugs)
	mean_num = len(filtered_msg) / (end_time - start_time).days

	print('过滤得到指定时间段内的bug数量为: {}'.format(len(filtered_msg)))
	print('max_num: {}'.format(max_num))
	print('min_num: {}'.format(min_num))
	print('mean_num: {}'.format(mean_num))

	draw_pic(daily_bugs, set_ts, start_time, end_time, sign)